//
//  HPZhijiaSwiper.m
//  HPZZTong
//
//  Created by WenJun on 14-6-16.
//  Copyright (c) 2014年 Handpay. All rights reserved.
//

#import "HPZhijiaSwiper.h"
#import "CSwiperController.h"
#import "SwipeInfo.h"
#import "SwiperUtils.h"


#define EncryptKey @"enc_key"
#define MAX_MAC_BLOCK_LEN  160

static HPZhijiaSwiper * zhijiaSwiper = nil;

@interface HPZhijiaSwiper()<CSwiperControllerDelegate>
{
    CSwiperController * _cswiper;
}
@end

@implementation HPZhijiaSwiper

+ (id)sharedInstance
{
    if (!zhijiaSwiper)
        zhijiaSwiper = [[super allocWithZone:NULL] init];
    return zhijiaSwiper;
}

- (id)init
{
    self = [super initWithSwiperQueue:dispatch_get_main_queue() wrapperQueue:dispatch_queue_create("zhijiaSwiper", 0)];
    return self;
}

- (void)releaseInstance
{
    [_cswiper stopCSwiper];
    [_cswiper releaseAudioResource];
    [_cswiper setDelegate:nil];
}

- (void)activeInstance
{
    _cswiper = [CSwiperController sharedController];
    _cswiper.delegate = self;
}

- (NSInvocation *)operationWithSelector:(SEL)selector
{
    NSInvocation * invocation = [NSInvocation invocationWithMethodSignature:[_cswiper methodSignatureForSelector:selector]];
    [invocation setTarget:_cswiper];
    [invocation setSelector:selector];
    return invocation;
}

- (void)getKSN:(SwiperComplete)complete
{
    if (self.ksn.length > 0)
    {
        ExecuteSwiperBlock(complete, [HPSwiperResult successResult:self.ksn]);
    }
    else if ([_cswiper isDevicePresent] || self.connectState >= SwiperStateDectedDevice)
    {
        [self connectStateChanged:SwiperStateConnecting];
        NSInvocation * operation = [self operationWithSelector:@selector(exchangeAPDU:)];
        NSString * apdu = @"00B0820010";
        [operation setArgument:&apdu atIndex:2];
        [self beginSwiperOperation:operation timeout:10 complete:complete];
    }
    else
    {
        ExecuteSwiperBlock(complete, [HPSwiperResult failResultWithCode:HPSwiperResultNotConnected]);
    }
}

- (void)encryptKeyData:(NSString *)keyData factor:(NSString *)factor complete:(SwiperComplete)complete
{
    [self encyptData:keyData factor:factor type:@"13" complete:complete];
}

- (void)encryptPin:(NSString *)pinStr factor:(NSString *)factor complete:(SwiperComplete)complete
{
    [self encyptData:pinStr factor:factor type:@"14" complete:complete];
}

- (void)encryptMac:(NSString *)mac factor:(NSString *)factor complete:(SwiperComplete)complete
{
    __block BOOL isNeedMulStep = NO;
    int index = 0;
    unsigned char tempApdu[512] = {0};
    char tempStr[512] = {0};
    const char* strByte = [mac UTF8String];
    __block int len = (int)[mac length] + 1;// 必须补80
    
    int needLen = len % 8;
    if (needLen > 0)
        len += (8 - needLen);
    len += 8; // 最前面强制补8个
    
    tempApdu[index++] = 0x80;
    tempApdu[index++] = 0xFA;
    __block int realLen = len;
    isNeedMulStep = (len > MAX_MAC_BLOCK_LEN);
    if (isNeedMulStep) {
        tempApdu[index++] = 0x07;
        realLen = MAX_MAC_BLOCK_LEN;
    }else{
        tempApdu[index++] = 0x05;
    }
    
    tempApdu[index++] = 0x00;
    tempApdu[index++] = realLen;
    
    index += 8;
    memcpy(tempApdu + index, strByte, [mac length]);
    index += [mac length];
    tempApdu[index] = 0x80;
    [SwiperUtils hexDecode:tempApdu lenght:realLen + 5 outputStrPoint:tempStr];
    
    NSString * macApdu = [NSString stringWithUTF8String:tempStr];
    __block SwiperComplete callback = complete;
    __block NSData * tempData = [NSData dataWithBytes:tempApdu length:512];
    [self encyptData:macApdu factor:factor type:@"15" complete:^(HPSwiperResult *swiperResult) {
        if (!isNeedMulStep)
        {
            callback(swiperResult);
        }
        else
        {
            char tempStr2[512] = {0};
            unsigned char tempApdu2[512] = {0};
            memcpy(tempApdu2, tempData.bytes, 512);
            tempApdu2[2] = 0x01;
            tempApdu2[4] = len - realLen;
            
            [SwiperUtils hexDecode:tempApdu2 lenght:5 outputStrPoint:tempStr2];
            [SwiperUtils hexDecode:tempApdu2 + realLen + 5 lenght:len - realLen outputStrPoint:tempStr2 + 10];
            
            NSInvocation * operation = [self operationWithSelector:@selector(exchangeAPDU:)];
            NSString * apdu = [NSString stringWithUTF8String:tempStr2];
            [operation setArgument:&apdu atIndex:2];
            [self beginSwiperOperation:operation timeout:10 complete:callback];
        }
    }];
}

- (void)encyptData:(NSString *)data factor:(NSString *)factor type:(NSString *)type complete:(SwiperComplete)complete
{
    if ([type isEqualToString:@"13"])
        data = [self packageDesApdu:data];
    else if ([type isEqualToString:@"14"])
        data = [NSString stringWithFormat:@"80FA00000806%@FFFFFFFF", data];

    NSMutableDictionary * apduDic = [NSMutableDictionary dictionary];
    [apduDic setObject:@[type, [factor substringToIndex:factor.length - 2], data] forKey:EncryptKey];
    NSInvocation * operation = [self operationWithSelector:@selector(batchExchangeAPDU:)];
    [operation setArgument:&apduDic atIndex:2];
    [self beginSwiperOperation:operation timeout:10 complete:complete];
}

//收款功能加密金额特殊处理，快速转账金额直接用关键数据加密
- (void)encyptAmount:(NSString *)amount factor:(NSString *)factor complete:(SwiperComplete)complete
{
    amount = [self packageAmount:amount];
    NSMutableDictionary * apduDic = [NSMutableDictionary dictionary];
    [apduDic setObject:@[@"13", [factor substringToIndex:factor.length - 2], amount] forKey:EncryptKey];
    NSInvocation * operation = [self operationWithSelector:@selector(batchExchangeAPDU:)];
    [operation setArgument:&apduDic atIndex:2];
    [self beginSwiperOperation:operation timeout:10 complete:complete];
}

- (NSString *)packageAmount:(NSString *)amount
{
    NSMutableString * result = [NSMutableString stringWithString:amount];
    
    for (NSInteger index = 0; result.length < 16; index ++)
        [result appendString:@"0"];
    
    return [NSString stringWithFormat:@"80FA000010%@",result];
}

// 确认金额
- (void)affirmAmount:(NSString *)amount time:(int)time complete:(SwiperComplete)complete
{
    complete([HPSwiperResult successResult:nil]);
}

// 刷卡
- (void)swipe:(int)time factor:(NSString *)factor complete:(SwiperComplete)complete
{
    NSInvocation * operation = [self operationWithSelector:@selector(startCSwiperWithRandomNumber:)];
    [operation setArgument:&factor atIndex:2];
    [self beginSwiperOperation:operation timeout:1000 complete:complete];
}

- (void)onGetFirmwareVersionCompleted:(NSString *)firmwareVersion {}
- (void)onGetKsnCompleted:(NSString *)ksn {}
- (void)onGetBatteryVoltageCompleted:(NSString *)batteryVoltage {}
- (void)onWaitingForDevice {}
- (void)onWaitingForCardSwipe {}
- (void)onCardSwipeDetected {}
- (void)onDecodingStart {}
- (void)onInterrupted {}

- (void)onIllegalStateError
{
    [self operationFinishedWithResult:[HPSwiperResult failResultWithCode:HPSwiperResultBusy]];
}

- (void)onTimeout
{
    [self operationFinishedWithResult:[HPSwiperResult failResultWithCode:HPSwiperResultTimeout]];
}

- (void)onDecodeError:(CSwiperControllerDecodeResult)decodeResult
{
    [self operationFinishedWithResult:[HPSwiperResult failResultWithCode:HPSwiperResultFail]];
}

- (void)onDecodeCompleted:(NSDictionary *)decodeData
{
    NSString* maskPan = [decodeData objectForKey:@"maskedPAN"];
    if (maskPan.length)
    {
        HPSwiperResult * result = [HPSwiperResult successResult:[self swipeInfoFromData:decodeData]];
        [self operationFinishedWithResult:result];
    }
    else
        [self operationFinishedWithResult:[HPSwiperResult failResultWithMsg:nil]];
}

- (SwipeInfo *)swipeInfoFromData:(NSDictionary *)decodeData
{
    SwipeInfo * swipeInfo = [[SwipeInfo alloc] init];
    NSMutableString * track2Str = [NSMutableString stringWithString:[decodeData objectForKey:@"encTrack2"]];
    
    while (track2Str.length < 40)
        [track2Str appendString:@"F"];
    
    swipeInfo.encTrack2 = track2Str;
    swipeInfo.plainAccount = [decodeData objectForKey:@"maskedPAN"];
    swipeInfo.dynamicKey = [[decodeData objectForKey:@"randomNumber"] uppercaseString];
    return swipeInfo;
}

- (void)onError:(int)errorType message:(NSString *)message
{
    [self operationFinishedWithResult:[HPSwiperResult failResultWithCode:HPSwiperResultFail]];
}

- (void)onNoDeviceDetected {}
- (void)onEncryptDataCompleted:(NSDictionary *)encryptDataResponse {}

- (void)onApduResponseReceived:(NSString *)response
{
    NSString * value = nil;
    if ([self checkResponse:response value:&value])
    {
        if (self.connectState == SwiperStateConnecting)
        {
            self.ksn = [value substringToIndex:20];
            [self connectStateChanged:SwiperStateConnected];
        }
        [self operationFinishedWithResult:[HPSwiperResult successResult:value]];
    }
    else
        [self operationFinishedWithResult:[HPSwiperResult failResultWithMsg:nil]];
}

- (void)onBatchApduResponseReceived:(NSDictionary *)apduResponses
{
    if ([[apduResponses allKeys] containsObject:EncryptKey])
    {
        NSString * value = nil;
        if ([self checkResponse:[apduResponses objectForKey:EncryptKey] value:&value])
            [self operationFinishedWithResult:[HPSwiperResult successResult:value]];
        else
            [self operationFinishedWithResult:[HPSwiperResult failResultWithMsg:nil]];
    }
    else
        [self operationFinishedWithResult:[HPSwiperResult successResult:apduResponses]];
}

-(NSString*)packageDesApdu:(NSString*)str
{
    int index = 0;
    unsigned char tempApdu[512] = {0};
    char tempStr[512] = {0};
    const char* strByte = [str UTF8String];
    int len = (int)[str length];
    int needLen = len % 8;
    
    if (needLen > 0)
        len += (8 - needLen);
    
    tempApdu[index++] = 0x80;
    tempApdu[index++] = 0xFA;
    tempApdu[index++] = 0x00;
    tempApdu[index++] = 0x00;
    tempApdu[index++] = len;
    
    memcpy(tempApdu + index, strByte, [str length]);
    [SwiperUtils hexDecode:tempApdu lenght:len+index outputStrPoint:tempStr];
    return [NSString stringWithUTF8String:tempStr];
}

- (void)onDevicePlugged { [self connectStateChanged:SwiperStateDectedDevice]; }
- (void)onDeviceUnplugged { [self connectStateChanged:SwiperStateNoDeviceDected]; }

- (BOOL)checkResponse:(NSString *)response value:(NSString **)value
{
    if ([response hasSuffix:@"9000"])
    {
        *value = [response substringToIndex:[response length] - 4];
        return YES;
    }
    return NO;
}

- (BOOL)canInputPin { return NO; }

- (void)stopSwiper
{
    [super stopSwiper];
    [_cswiper stopCSwiper];
}
@end